<template>
	<el-form ref="form" v-if="model" :validate-on-rule-change="false" :model="model" :rules="rules" v-bind="$attrs">
		<template v-for="(item, index) in options" :key="index">

			<el-form-item v-if="!item.children || !item.children.length" :prop="item.prop"
				:label="item.label">

				<component style="width: 300px;" v-if="item.type !== 'upload' && item.type !== 'editor'"
					:placeholder="item.placeholder" v-model="model[item.prop]" v-bind="item.attrs"
					:is="`el-${item.type}`"></component>

				<el-upload v-if="item.type === 'upload'" :http-request="httpRequest" :on-exceed="onExceed"
					:before-upload="beforeUpload" :before-remove="beforeRemove" :on-change="onChange"
					:on-progress="onProgress" :on-error="onError" :on-success="onSuccess" :on-remove="onRemove"
					:on-preview="onPreview" v-bind="item.uploadAttrs">
					<slot name="default"></slot>
					<slot name="tip"></slot>
				</el-upload>

				<div id="editor" v-if="item.type === 'editor'"></div>
			</el-form-item>

			<el-form-item v-if="item.children && item.children.length" style="width: 300px;" :prop="item.prop"
				:label="item.label">
				<component style="width: 100%;" :placeholder="item.placeholder" v-model="model[item.prop]"
					v-bind="item.attrs" :is="`el-${item.type}`">
					<component :is="`el-${child.type}`" v-for="(child, i) in item.children" :key="i"
						:label="child.label" :value="child.value"></component>
				</component>
			</el-form-item>
		</template>

		<el-form-item>
			<slot name="action" :form="form" :model="model"></slot>
		</el-form-item>
	</el-form>
</template>

<script lang="ts" setup name="xform">
	import E from 'wangeditor'

	import {
		ref,
		onMounted,
		watch,
		nextTick
	} from 'vue'
	import cloneDeep from 'lodash/cloneDeep'

	let props = defineProps({
		options: {
			type: Array,
			required: true
		},

		httpRequest: {
			type: Function
		}
	})

	let model = ref({})
	let rules = ref({})
	let form = ref()
	let edit = ref()
	
	let resetFields = () => {
		form.value.resetFields()
		if(props.options && props.options.length) {
			let editorItem = props.options.find(item => item.type === 'editor')
			edit.value.txt.html(editorItem.value)
		}
	}
	
	let validate = () => {
		return form.value.validate
	}
	
	let getFormData = () => {
		return model.value
	}
	
	defineExpose({
		resetFields,
		validate,
		getFormData
	})
	
	let initForm = () => {
		if (props.options && props.options.length) {
			let m = {}
			let r = {}

			props.options.map(item => {
				m[item.prop] = item.value
				r[item.prop] = item.rules

				if (item.type === 'editor') {
					nextTick(() => {
						if (document.getElementById('editor')) {
							const editor = new E('#editor')
							editor.config.placeholder = item.placeholder
							editor.create()
							editor.txt.html(item.value)	
							editor.config.onchange = newHtml => {
								model.value[item.prop] = newHtml
							}
							edit.value = editor
						}
					})
				}
			})
			model.value = cloneDeep(m)
			rules.value = cloneDeep(r)
		}
	}

	onMounted(() => {
		initForm()
	})

	watch(() => props.options, () => {
		initForm()
	}, {
		deep: true
	})

	let emits = defineEmits(['on-preview', 'on-remove', 'on-success', 'on-error', 'on-progress', 'on-change',
		'before-upload', 'before-remove', 'on-exceed'
	])

	let onPreview = file => {
		emits('on-preview', file)
	}

	let onRemove = (file, fileList) => {
		emits('on-remove', {
			file,
			fileList
		})
	}

	let onSuccess = (response, file, fileList) => {
		let uploadItem = props.options.find(item => item.type === 'upload')
		model.value[uploadItem.prop] = {
			response,
			file,
			fileList
		}

		emits('on-success', {
			response,
			file,
			fileList
		})
	}

	let onError = (err, file, fileList) => {
		emits('on-error', {
			err,
			file,
			fileList,
		})
	}

	let onProgress = (event, file, fileList) => {
		emits('on-progress', {
			event,
			file,
			fileList
		})
	}

	let onChange = (file, fileList) => {
		emits('on-change', {
			file,
			fileList
		})
	}

	let beforeRemove = (file, fileList) => {
		emits('before-remove', {
			file,
			fileList
		})
	}

	let beforeUpload = file => {
		emits('before-upload', file)
	}

	let onExceed = (files, fileList) => {
		emits('on-exceed', {
			files,
			fileList
		})
	}
</script>

<style scoped>

</style>
